//Copyright 2007 Iain Bapty
//
//This file is part of the ITunes Tag Manager.
//
//ITunes Tag Manager is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//ITunes Tag Manager is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with ITunes Tag Manager.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using iTunesLib;

namespace ITunesManager
{
    class Manager
    {
        private iTunesApp app;
        private IITTrackCollection tracks;
        private IList<string> libraryFilePaths;
        private int missingFilesDeleted;
        private int addedFilesToLibraryOK;
        private int addedFilesToLibraryNotOk;

        public Manager() 
        { 
            app = new iTunesAppClass(); 
        }

        /// <summary>
        /// Plays the currently selected file
        /// </summary>
        public void Play()
        {
            app.Play();
        }

        /// <summary>
        /// Pauses the currently playing flie.
        /// </summary>
        public void Pause()
        {
            app.Pause();
        }

        /// <summary>
        /// Returns a list of ITunes tracks where the artist's names are capitalised.
        /// </summary>
        /// <returns>List of tracks</returns>
        public List<IITTrack> GetArtists_Capitalised()
        {
            List<IITTrack> matchedtracks = new List<IITTrack>();
            tracks = app.LibraryPlaylist.Tracks;

            for (int i = 0; i < tracks.Count; i++)
            {
                IITTrack track = tracks[i + 1];

                bool AllCaps = true;
                if (track.Artist != null && track.Artist.Length > 0)
                {
                    foreach (char artistChar in track.Artist)
                    {
                        if (Char.IsLower(artistChar) && !Char.IsWhiteSpace(artistChar) && !Char.IsSymbol(artistChar))
                        {
                            AllCaps = false;
                            break;
                        }
                    }

                    if (AllCaps)
                    {
                        matchedtracks.Add(track);
                    }
                }
            }

            return matchedtracks;
        }

        /// <summary>
        /// Deletes files from the ITunes library if the corresponding physical file cannot be found.
        /// </summary>
        public void DeleteMissingFiles()
        {
            tracks = app.LibraryPlaylist.Tracks;
            missingFilesDeleted = 0;

            for (int i = 0; i < tracks.Count; i++)
            {
                IITTrack track = tracks[i + 1];
                
                if(track is IITFileOrCDTrack)
                {
                    IITFileOrCDTrack fileTrack = (IITFileOrCDTrack) track;
                    Boolean fileExists = File.Exists(fileTrack.Location);
                    if (!fileExists)
                    {
                        fileTrack.Delete();
                        missingFilesDeleted++;
                    }
                }
            }
        }

        /// <summary>
        /// Gets the number of deleted entries by the previous call to DeleteMissingFiles().
        /// </summary>
        /// <value>The number of deleted library entries.</value>
        public int MissingFilesDeleted { get { return this.missingFilesDeleted; } }

        /// <summary>
        /// Gets number of files added to the library.
        /// </summary>
        /// <value>The number of files added to library OK.</value>
        public int AddedFilesToLibraryOK { get { return this.addedFilesToLibraryOK; } }

        /// <summary>
        /// Gets number of files not added to the library.
        /// </summary>
        /// <value>The number of files not added to library OK.</value>
        public int AddedFilesToLibraryNotOk { get { return this.addedFilesToLibraryNotOk; } }

        /// <summary>
        /// Adds any files to the library which aren't currently in the library
        /// </summary>
        /// <param name="searchPath">The search path.</param>
        public void FindFilesNotInLibrary(string searchPath)
        {
            RecordLocalListOfLibraryFiles();
            IList<string> missingFiles = RecursivelyFindFilesNotInLibrary(searchPath);

            this.addedFilesToLibraryOK = 0;
            this.addedFilesToLibraryNotOk = 0;
            foreach(string missingFile in missingFiles)
            {
                try
                {
                    IITOperationStatus status = app.LibraryPlaylist.AddFile(missingFile);
                    if (null == status)
                    {
                        this.addedFilesToLibraryNotOk++;
                    }
                    else
                    {
                        this.addedFilesToLibraryOK++;
                    }
                }
                catch (Exception e)
                {
                    this.addedFilesToLibraryNotOk++;
                }
            }
        }

        /// <summary>
        /// Given a file path, checks to see if the files in that path (any subfolders) are in the ITunes Library.
        /// </summary>
        /// <param name="folderPath">The path to the folder to search.</param>
        /// <returns>A list of files found which are not in the ITunes library</returns>
        private IList<string> RecursivelyFindFilesNotInLibrary(string folderPath)
        {
            String[] files = Directory.GetFiles(folderPath);
            IList<string> missingFiles = new List<String>();

            foreach (string filePath in files)
            {
                bool fileIsSupported = filePath.EndsWith("mp3");
                if (!fileIsSupported)
                {
                    continue;
                }
                if (!FindFileInLocalListOfLibraryFiles(filePath))
                {
                    missingFiles.Add(filePath);
                }
            }

            String[] subDirectories = Directory.GetDirectories(folderPath);

            foreach (string subDirectory in subDirectories)
            {
                foreach (string missingFilePath in RecursivelyFindFilesNotInLibrary(subDirectory))
                {
                    missingFiles.Add(missingFilePath);
                }
            }

            return missingFiles;
        }

        /// <summary>
        /// Finds the file in local list of library files.
        /// </summary>
        /// <param name="filePath">File path to check.</param>
        /// <returns>True if file is found. Otherwise False.</returns>
        private bool FindFileInLocalListOfLibraryFiles(string filePath)
        {
            if (this.libraryFilePaths.Contains(filePath))
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// Make a local list of files in the ITunes Library.
        /// </summary>
        private void RecordLocalListOfLibraryFiles()
        {
            this.libraryFilePaths = new List<String>();
            this.tracks = app.LibraryPlaylist.Tracks;
            int trackCount = this.tracks.Count;

            for (int i = 0; i < trackCount; i++)
            {
                IITTrack track = this.tracks[i + 1];

                if (track is IITFileOrCDTrack)
                {
                    IITFileOrCDTrack fileTrack = (IITFileOrCDTrack)track;
                    this.libraryFilePaths.Add(fileTrack.Location);
                }
            }
        }

    }
}
